﻿using System;
using System.Collections.Generic;
using Jayden.Dll.Cards.Enums;

namespace Jayden.Dll.Cards.Poker
{
	public class TexasHoldemHandCategory : IComparable<TexasHoldemHandCategory>
	{
		private CardRank[] m_Ranks;
		private bool m_IsSuited;

		private TexasHoldemHandCategory() { }
		public TexasHoldemHandCategory(CardRank rank1, CardRank rank2, bool suited = false)
		{
			if (rank1.CompareTo(rank2) < 0)
				throw new Exception("Invalid order");
			m_Ranks = new CardRank[] { rank1, rank2 };
			m_IsSuited = suited;
		}
		public TexasHoldemHandCategory(Card card1, Card card2)
		{
			if (card1 == null || card2 == null)
				throw new NullReferenceException();
			if (card1.Equals(card2))
				throw new Exception("Same cards ...");
			List<CardRank> ranks = new List<CardRank>();
			ranks.Add(card1.Rank);
			ranks.Add(card2.Rank);
			ranks.Sort();
			ranks.Reverse();
			m_Ranks = ranks.ToArray();
			m_IsSuited =card1.Suit.Equals(card2.Suit);
			CheckValidity();
		}

		private void CheckValidity()
		{
			if (m_Ranks[0].Equals(m_Ranks[1]) && m_IsSuited)
				throw new Exception("Invalid suited pair ...");
		}

		public float ChenFormula
		{
			get
			{
				float points = 0;
				switch (m_Ranks[0])
				{
					case CardRank.Jack:
						points = 6;
						break;
					case CardRank.Queen:
						points = 7;
						break;
					case CardRank.King:
						points = 8;
						break;
					case CardRank.Ace:
						points = 10;
						break;
					default:
						points = ((int)m_Ranks[0] + 2) * 0.5f;
						break;
				}
				if (IsPair)
					points = Math.Max(5, points * 2);
				else
				{
					int gap = (m_Ranks[0] - m_Ranks[1]) - 1;
					if (gap < 3)
						points -= gap;
					else if (gap == 3)
						points -= 4;
					else if (gap > 3)
						points -= 5;
				}
				if (IsSuited)
					points += 2;
				return points;
			}
		}
		public bool IsSuited { get { return m_IsSuited; } }
		public bool IsPair { get { return m_Ranks[0].Equals(m_Ranks[1]); } }
		public CardRank this[int index] { get { return m_Ranks[index]; } }

		public override string ToString()
		{
			if(m_IsSuited)
				return Card.GetRankChar(m_Ranks[0]) + "" + Card.GetRankChar(m_Ranks[1]) + "s";
			if(IsPair)
				return Card.GetRankChar(m_Ranks[0]) + "" + Card.GetRankChar(m_Ranks[1]);
			return Card.GetRankChar(m_Ranks[0]) + "" + Card.GetRankChar(m_Ranks[1]) + "o";
		}
		public override int GetHashCode()
		{
			return (m_Ranks[0].GetHashCode() + m_Ranks[1].GetHashCode() * 31) * (m_IsSuited ? 3 : 1);
		}
		public override bool Equals(object obj)
		{
			if (!(obj is TexasHoldemHandCategory))
				return false;
			TexasHoldemHandCategory other = obj as TexasHoldemHandCategory;
			return other.m_IsSuited == m_IsSuited && other.m_Ranks[0].Equals(m_Ranks[0]) && m_Ranks[1].Equals(other.m_Ranks[1]);
		}

		public int CompareTo(TexasHoldemHandCategory other)
		{
			if (IsPair && !other.IsPair)
				return 1;
			if (!IsPair && other.IsPair)
				return -1;
			if (m_IsSuited && !other.m_IsSuited)
				return 1;
			if (!m_IsSuited && other.m_IsSuited)
				return -1;
			int v1 = (int)m_Ranks[0];
			int v2 = (int)other.m_Ranks[0];
			if (v1 == v2)
			{
				v1 = (int)m_Ranks[1];
				v2 = (int)other.m_Ranks[1];
				if (v1 == v2)
					return 0;
			}
			return v1.CompareTo(v2);
		}

		public static TexasHoldemHandCategory Parse(string value)
		{
			TexasHoldemHandCategory categ = new TexasHoldemHandCategory();
			if (value.Length == 3)
			{
				if (value[2] == 's')
					categ.m_IsSuited = true;
				else if (value[2] == 'o')
					categ.m_IsSuited = false;
				else
					throw new Exception("Invalid format");
			}
			else if (value.Length == 2 && value[0] != value[1])
				throw new NotImplementedException();

			CardRank rank1 = Card.ParseRank(value[0]);
			CardRank rank2 = Card.ParseRank(value[1]);
			List<CardRank> ranks = new List<CardRank>();
			ranks.Add(rank1);
			ranks.Add(rank2);
			ranks.Sort();
			ranks.Reverse();
			categ.m_Ranks = ranks.ToArray();
			categ.CheckValidity();
			return categ;
		}
	}
}
